import re, time, json, logging, hashlib, base64, asyncio
from www.apis import Page, APIValueError, APIResourceNotFoundError,APIError,APIPermissionError
from www.coroweb import get, post
from aiohttp import web
import orm

from www.models import User, Comment, Blog, next_id

COOKIE_NAME ='awesession'
_COOKIE_KEY = 'Awesome'


def get_page_index(page_str):
    p = 1
    try:
        p = int(page_str)
    except ValueError as e:
        pass
    if p < 1:
        p = 1
    return p


def user2cookie(user, max_age):
    expires = str(int(time.time() + max_age))
    # SHA1("用户id" + "用户口令" + "过期时间" + "SecretKey")
    # 当浏览器发送cookie到服务端后，服务器可以拿到的信息包括
    # 用户ID， 过期时间，SHA1值
    s = '%s-%s-%s-%s' % (user.id, user.passwd, expires, _COOKIE_KEY)
    L = [user.id, expires, hashlib.sha1(s.encode('utf-8')).hexdigest()]
    return '-'.join(L)

# 主页
@get('/')
async def index(*, page='1'):
    page_index = get_page_index(page)
    num = await Blog.findNumber('count(id)')
    page = Page(num, page_index, page_size=5) # 每页5个博客
    if num == 0:
        blogs = []
    else:
        blogs = await Blog.findAll(orderBy='created_at desc', limit=(page.offset, page.limit))
    return {
        '__template__': 'blogs.html',
        'page': page,
        'blogs': blogs
    }


# 注册页：GET /register
@get('/register')
async def register():
    return {
        '__template__': 'register.html'
    }


# 登录页：GET /signin
@get('/signin')
async def signin():
    return {
        '__template__': 'signin.html'
    }


@get('/api/users111')
def api_get_users():

    users = yield from User.findAll(orderBy='created_at desc')
    return dict(users=users)

_RE_EMAIL = re.compile(r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$')
_RE_SHA1 = re.compile(r'^[0-9a-f]{40}$')


# 创建新用户：POST /api/users
@post('/api/users')
async def api_register_user(*, email, name, passwd):
    if not name or not name.strip():
        raise APIValueError('name')
    if not email or not _RE_EMAIL.match(email):
        raise APIValueError('email')
    if not passwd or not _RE_SHA1.match(passwd):
        raise APIValueError('passwd')
    users = await  User.findAll('email=?',[email])
    if len(users) > 0:
        raise APIError('register:failed', 'email', 'Email is already in use')
    uid = next_id()
    sha1_passwd = '%s:%s' % (uid, passwd)
    user = User(id=uid, name=name.strip(), email=email,
                passwd=hashlib.sha1(sha1_passwd.encode('utf-8')).hexdigest(),
                image='http://www.gravatar.com/avatar/%s?d=mm&s=120' % hashlib.md5(email.encode('utf-8')).hexdigest())
    print('user',user)
    await user.save()
    print(user)
    r = web.Response()
    r.set_cookie(COOKIE_NAME, user2cookie(user, 86400),max_age=86400, httponly=True)
    user.passwd = '******'
    r.content_type = 'application/json'
    r.body = json.dumps(user, ensure_ascii=False).encode('utf-8')
    return r


# 用户登录：POST /api/authenticate
# user sign in
@post('/api/authenticate')
async def authenticate(*, email, passwd):
    if not email:
        raise APIValueError('email', 'Invalid email.')
    if not passwd:
        raise APIValueError('passwd', 'Invalid password.')
    user = await User.findAll('email=?',[email])
    if len(user) == 0:
        raise APIValueError('email', 'Email not exist.')
    user = user[0]

    #check passwd
    sha1 = hashlib.sha1()
    sha1.update(user.id.encode('utf-8'))
    sha1.update(b':')
    sha1.update(passwd.encode('utf-8'))
    print(sha1.hexdigest())
    print(user.passwd)
#    if user.passwd != sha1.hexdigest():
#        raise APIValueError('passwd', 'Invalid password')
    r = web.Response()
    r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
    r.content_type = 'application/json'
    r.body = json.dumps(user, ensure_ascii=False).encode('utf-8')
    return r


def check_admin(request):
    if request.__user__ is None : # or not request.__user__.admin
        raise APIPermissionError('user is None or user.admin=0.')


# 创建日志页：GET /manage/blogs/create
@get('/manage/blogs/create')
def manage_create_blog():
    return {
        '__template__': 'manage_blog_edit.html',
        'id': '',
        'action': '/api/blogs'
    }


@get('/manage/blogs')
def manage_blogs(*, page='1'):
    return{
        '__template__': 'manage_blogs.html',
        'page_index': get_page_index(page)
    }

@get('/manage/blogs/edit')
def manage_edit_blog(*, id):
    return{
        '__template__': 'manage_blog_edit.html',
        'id': id,
        'action': '/api/blogs/%s' % id
    }


@get('/api/blogs')
async def api_blogs(*, page='1'):
    page_index = get_page_index(page)
    num = await Blog.findNumber('count(id)')
    p = Page(num, page_index)
    if num == 0:
        return dict(page=p, blogs=())
    blogs = await  Blog.findAll(orderBy='created_at desc', limit=(p.offset, p.limit))
    return dict(page=p, blogs=blogs)


@get('/blog/{id}')
async def get_blog(*, id):
    blog = await Blog.find(id)
    comment = None
    blog.html_content = blog.content
    return{
        '__template__': 'blog.html',
        'blog': blog,
        'comment': comment
    }

# 获取日志：GET /api/blogs
@get('/api/blogs/{id}')
async def api_get_blog(*, id):
    blog = await Blog.find(id)
    return blog

@post('/api/blogs/{id}')
async def api_update_blog(request, *, id, name, summary, content):
    check_admin(request)
    blog = await Blog.find(id)
    if not name or not name.strip():
        raise APIValueError('name', 'name cannot be empty.')
    if not summary or not summary.strip():
        raise APIValueError('summary', 'summary cannot be empty.')
    if not content or not content.strip():
        raise APIValueError('content', 'content cannot be empty.')
    blog.name = name.strip()
    blog.summary = summary.strip()
    blog.content = content.strip()
    await blog.update()
    return blog


# 创建日志：POST /api/blogs
@post('/api/blogs')
async def api_create_blog(request, *, name, summary, content):
    check_admin(request)
    if not name or not name.strip():
        raise APIValueError('name', 'name cannot be empty.')
    if not summary or not summary.strip():
        raise APIValueError('summary', 'summary cannot be empty.')
    if not content or not content.strip():
        raise APIValueError('content', 'content cannot be empty.')
    blog = Blog(user_id=request.__user__.id, user_name=request.__user__.name,
                user_image=request.__user__.image, name=name.strip(), summary=summary.strip(),
                content=content.strip())
    await blog.save()
    return blog









